/*
 * igo: com.cctv.igo.security.ManagerFilterInvocationSecurityMetadataSource.java Create On 2011-5-20 下午02:43:59 By Q-Wang
 * $Revision: 1.1 $
 */
package com.ctvit.framework.security;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.UrlMatcher;

import com.ctvit.framework.security.service.AuthorizationService;
import com.ctvit.framework.web.context.ContextHolder;


/**
 * @author <a href="mailto:apeidou@gmail.com">Q-Wang</a>
 *
 */
public class ManagerFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

	//	private static final Set<String> HTTP_METHODS = new HashSet<String>(Arrays.asList("DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT", "TRACE"));

	protected final Logger logger = LoggerFactory.getLogger(getClass());

	private UrlMatcher urlMatcher;

	private boolean stripQueryStringFromUrls;

	/**
	 * @param urlMatcher the urlMatcher to set
	 */
	public void setUrlMatcher(UrlMatcher urlMatcher) {
		this.urlMatcher = urlMatcher;
	}

	/**
	 * @param stripQueryStringFromUrls the stripQueryStringFromUrls to set
	 */
	public void setStripQueryStringFromUrls(boolean stripQueryStringFromUrls) {
		this.stripQueryStringFromUrls = stripQueryStringFromUrls;
	}

	//	private Map<String, Map<Object, Collection<ConfigAttribute>>> httpMethodMap =
	//		new HashMap<String, Map<Object, Collection<ConfigAttribute>>>();

	/**
	 * @see org.springframework.security.access.SecurityMetadataSource#getAttributes(java.lang.Object)
	 */
	public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
		if ((object == null) || !this.supports(object.getClass())) {
			throw new IllegalArgumentException("Object must be a FilterInvocation");
		}

		String url = ((FilterInvocation) object).getRequestUrl();
		String method = ((FilterInvocation) object).getHttpRequest().getMethod();

		return lookupAttributes(url, method);
	}

	public final Collection<ConfigAttribute> lookupAttributes(String url, String method) {
		if (stripQueryStringFromUrls) {
			// Strip anything after a question mark symbol, as per SEC-161. See also SEC-321
			int firstQuestionMarkIndex = url.indexOf("?");

			if (firstQuestionMarkIndex != -1) {
				url = url.substring(0, firstQuestionMarkIndex);
			}
		}

		if (urlMatcher.requiresLowerCaseUrl()) {
			url = url.toLowerCase();

			if (logger.isDebugEnabled()) {
				logger.debug("Converted URL to lowercase, from: '" + url + "'; to: '" + url + "'");
			}
		}

		// Obtain the map of request patterns to attributes for this method and lookup the url.
		//		Collection<ConfigAttribute> attributes = extractMatchingAttributes(url, httpMethodMap.get(method));
		Collection<ConfigAttribute> attributes = extractMatchingAttributes(url);

		// If no attributes found in method-specific map, use the general one stored under the null key
		//		if (attributes == null) {
		//			attributes = extractMatchingAttributes(url, httpMethodMap.get(null));
		//		}

		return attributes;
	}

	//	private Collection<ConfigAttribute> extractMatchingAttributes(String url, Map<Object, Collection<ConfigAttribute>> map) {
	private Collection<ConfigAttribute> extractMatchingAttributes(String url) {

		final boolean debug = logger.isDebugEnabled();
		AuthorizationService authorizationService = (AuthorizationService)ContextHolder.getBean(AuthorizationService.class);
		Map<String, Collection<ConfigAttribute>> map = authorizationService.loadAllConfigAttribute();
		for (Entry<String, Collection<ConfigAttribute>> entry:map.entrySet()) {
			String resource = entry.getKey();
			boolean matched = urlMatcher.pathMatchesUrl(resource, url);
			if (debug) {
				logger.debug("Candidate is: '" + url + "'; pattern is " + resource + "; matched=" + matched);
			}
			if (matched) {
				return entry.getValue();
			}
		}
		return null;
	}

	/**
	 * @see org.springframework.security.access.SecurityMetadataSource#getAllConfigAttributes()
	 */
	public Collection<ConfigAttribute> getAllConfigAttributes() {

		//AuthorizationService authorizationService = ContextHolder.getBean(AuthorizationService.class);
		return Collections.emptyList();
		//		return authorizationService.listAllConfigAttributes();
	}

	/**
	 * @see org.springframework.security.access.SecurityMetadataSource#supports(java.lang.Class)
	 */
	public boolean supports(Class<?> clazz) {
		return FilterInvocation.class.isAssignableFrom(clazz);
	}

	protected UrlMatcher getUrlMatcher() {
		return urlMatcher;
	}

	public boolean isConvertUrlToLowercaseBeforeComparison() {
		return urlMatcher.requiresLowerCaseUrl();
	}

}
